home *** CD-ROM | disk | FTP | other *** search
/ NetNews Offline 2 / NetNews Offline Volume 2.iso / news / comp / std / c++ / 285 < prev    next >
Encoding:
Internet Message Format  |  1996-08-06  |  8.9 KB

  1. From: kanze@lts.sel.alcatel.de (James Kanze US/ESC 60/3/141 #40763)
  2. Message-ID: <KANZE.96Feb5132431@slsvewt.lts.sel.alcatel.de>
  3. X-Original-Date: 05 Feb 1996 12:24:28 GMT
  4. Path: in1.uu.net!bounce-back
  5. Date: 06 Feb 96 02:35:51 GMT
  6. Approved: fjh@cs.mu.oz.au
  7. Newsgroups: comp.std.c++
  8. Subject: Re: class.union questions
  9. In-Reply-To: dirk@becker.adviser.com's message of 03 Feb 96 17:22:11 GMT
  10. Organization: SEL
  11. References: <v01530500ad38ee830c96@[194.163.74.11]>
  12. Apparently-To: std-c++@ncar.ucar.edu
  13. X-Auth: PGPMoose V1.1 PGP comp.std.c++
  14.     iQBFAgUBMRa+ouEDnX0m9pzZAQE6CAF9ENug9/g7C1pecakAJvzfFetiirJEg3Uv
  15.     TwmlbBbghQgvuIAfGBInIk2kxgowu6Aj
  16.     =yvyy
  17.  
  18. In article <v01530500ad38ee830c96@[194.163.74.11]>
  19. dirk@becker.adviser.com (Dirk Becker) writes:
  20.  
  21. |> In Section 9.6.1 Unions [class.union] there is a large collection of
  22. |> restrictions on the union itself and on candidate member classes.
  23. |> I would like to ask for reasons of several of them:
  24.  
  25. One of the principle goals was that a union be compatible with a C
  26. union, at least in use.  One of the rules is that the addresses of all
  27. of the elements in the union compare equal to the address of the union
  28. itself, when cast to the appropriate type.
  29.  
  30. |> a)  "A union shall not have base classes. A union shall not be used as
  31. |>      a base class."
  32.  
  33. Without this rule, you either break the address rule, or you impose
  34. some special class layout on unions.
  35.  
  36. |> This prevents any construction like the following, where one would
  37. |> like to extend the union contained in some base class:
  38.  
  39. |> class GenericInterpreter {
  40. |>     union opcode {
  41. |>         short tag;
  42. |>         struct { short tag; short data; } op1;
  43. |>         struct { short tag; char* data; } op2;
  44. |>     };
  45. |> };
  46.  
  47. |> class SpecialInterpreter : public GenericInterpreter {
  48. |>     union opcode : public GenericInterpreter::opcode {
  49. |>         struct { short tag; long  data; } op3;
  50. |>         struct { short tag; float data; } op4;
  51. |>     };
  52. |> };
  53.  
  54. This is generally handled better by an abstract base class and virtual
  55. functions.
  56.  
  57. |> b) "An object of a class with a non-trivial default constructor
  58. |>     (_class.ctor_), a non-trivial copy constructor (_class.copy_),
  59. |>     a non-trivial destructor (_class.dtor_), or a non-trivial copy
  60. |>     assignment operator (_over.ass_, _class.copy_) cannot be a member
  61. |>     of a union,"
  62.  
  63. |> This is a major reduction of the restrictions found in ARM, where all
  64. |> kinds of constructors or assignment operators were excluded. Here is
  65. |> also a note to give the explanation by the assumption, any member
  66. |> functions and especially assignments would usually expect a correctly
  67. |> constructed object.
  68.  
  69. This is, in fact, exactly the restriction in the ARM.  All that has
  70. changes is the way things are described.  In the ARM, classes may or
  71. may not have constructors (destructors, assignment operators).  In the
  72. current standard, *EVERY* class/struct has a copy constructor, an
  73. assignment operator and a destructor; the distinction is that some of
  74. these are trivial.
  75.  
  76. A user declared constructor, destructor or assignment operator is by
  77. definition never trivial.
  78.  
  79. |> The quoted WP sequence tries its best to exclude virtual function
  80. |> tables from the union members, which is just fine. But through the
  81. |> non-trivialness you also exclude _any_ custom make of the copy
  82. |> constructor and assignment operator.
  83. |> So you can have any special assignment operator or constructor for
  84. |> your member objects, any but the most common and useful ones.
  85.  
  86. Correct.  The reason is simple: assignment, copy, default construction
  87. and destruction of a union must be correctly defined without the
  88. compiler knowing which element the union actually contains.  The set
  89. of forbidden operators are those that the compiler might be called
  90. upon to use in implicitly generated code.
  91.  
  92. |> Another sample:
  93.  
  94. |> class longlong { ... };
  95. |> struct opcode {
  96. |>     short tag;
  97. |>     union {
  98. |>         short     op1;
  99. |>         long      op2;
  100. |>         longlong  op3;
  101. |>     } data;
  102. |> };
  103.  
  104. |> If you are lucky to have some native long long datatype, then this
  105. |> would be legal code. If you already had to implement your own
  106. |> class longlong, now you lost the chance to use it (here).
  107.  
  108. This is a problem, but... how would the compiler know when to call the
  109. constructor/destructor of your longlong?
  110.  
  111. |> c) "A union can be thought of as a class"
  112.  
  113. |> Here you accept the implications of 12.8.8 and 12.8.13 on implicitly
  114. |> defined copy constructor and copy assignment. The already trivial
  115. |> copy constructor/assignment of the member objects will then result
  116. |> in one large repetition of copies from and to the same memory locations.
  117. |> To avoid this behaviour I would strongly recommend to implement your
  118. |> own copy constructor or assignment whenever you use a union, because a
  119. |> memberwise copy is usually not desired.
  120.  
  121. Basically, if you study the restrictions on unions carefully, the
  122. rules are such that a bitwise copy *must* be legal for assignment and
  123. copy construction.  This is the only type of copy the compiler can
  124. cope with in the absense of a discriminator to tell it which element
  125. of the union is valid.
  126.  
  127. IMHO: if you feel that your union needs a copy constructor or an
  128. assignment operator, you are probably doing something wrong, in the
  129. sense that you are trying to use unions in a way that they are not
  130. intended.  (As they are defined in the standard.  If they were defined
  131. differently, they might have different reasonable uses.)
  132.  
  133. In practice, I don't think I've used a union in my code since
  134. switching to C++, except in memory management code (ensuring
  135. alignment, etc.).
  136.  
  137. |> Let's combine this with the problems of a) and b):
  138.  
  139. |> class GenericInterpreter {
  140. |>     union opcode {
  141. |>         opcode(const opcode&);               // replace implicitly defined
  142. |>         opcode& operator = (const opcode&);  // memberwise copy versions
  143.  
  144. |>         short tag;
  145. |>         struct { short tag; short data; } op1;
  146. |>         struct { short tag; char* data; } op2;
  147. |>     };
  148. |> };
  149.  
  150. |> class SpecialInterpreter : public GenericInterpreter {
  151. |>     union opcode {
  152. |>         GenericInterpreter::opcode generic; // error: non-trivial member
  153. |>         short tag;
  154. |>         struct { short tag; long  data; } op3;
  155. |>         struct { short tag; float data; } op4;
  156. |>     };
  157. |> };
  158.  
  159. |> class ValidInterpreter : public GenericInterpreter {
  160. |>     union opcode {
  161. |>         // using copy - paste instead of language features
  162. |>         short tag;
  163. |>         struct { short tag; short data; } op1;
  164. |>         struct { short tag; char* data; } op2;
  165. |>         //
  166. |>         struct { short tag; long  data; } op3;
  167. |>         struct { short tag; float data; } op4;
  168. |>     };
  169. |> };
  170.  
  171. |> In my opinion, comparing the copy constructor/assignments to others, they
  172. |> are only special regarding their use by the implicitly defined memberwise
  173. |> copy constructor/assignment by outside classes. Here I can't find a reason
  174. |> why a member's custom copy methods should not be applicable instead.
  175.  
  176. |> Conclusion, just dreaming:
  177. |>  I would generally prefer " ... constructors and destructor of member
  178. |>  objects are ignored, if not explicitly called by the union's ctor/dtor.
  179. |>  The union's implicit default copy constructor / assignment does a
  180. |>  binary copy instead of memberwise copy. Objects <containing a vptr>
  181. |>  cannot be member of a union" - Please pardon my shortcut on vptrs.
  182.  
  183. There was some discussion concerning this.  There were two points of
  184. view: one supported basically what you are proposing, the other the
  185. current situation.  The current situation won.
  186.  
  187. I argued the current situation on the grounds that the above is just
  188. too dangerous.  Basically, it makes it too simple to access
  189. unconstructed objects of types which require a constructor.  Most of
  190. the uses I see for a union are at the low level, where C like code is
  191. perfectly appropriate.
  192.  
  193. IMHO, things like your example are much better handled with derived
  194. classes (in which the vptr replaces the tag for type information).
  195. Even in cases where the union might be more appropriate, what would be
  196. needed is a discriminated union, which is a completely different beast
  197. than the union we now have.  (I've yet to see what I would consider a
  198. convincing example of the advantage of a discriminated union over
  199. polymorphism, but I know that others disagree with me here.)
  200.  
  201. |> d) anonymous union
  202.  
  203. |> Why is there no anonymous struct? This is not only for symmetric reasons,
  204. |> but anonymous structs inside unions may be as useful as anonymous unions
  205. |> inside structs.
  206.  
  207. Agreed here.  Although I really don't see it as worth the bother.  (I
  208. could do without anonymous unions, too.)
  209. --
  210. James Kanze         Tel.: (+33) 88 14 49 00        email: kanze@gabi-soft.fr
  211. GABI Software, Sarl., 8 rue des Francs-Bourgeois, F-67000 Strasbourg, France
  212. Conseils, itudes et rialisations en logiciel orienti objet --
  213.                 -- A la recherche d'une activiti dans une region francophone
  214. ---
  215. [ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  216.   Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  217.   is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
  218.